/****************************************************************
 * * Product  :   HP Subscriber Network Application Policy
 * * Module   :   gr-manager
 * * Date: Apr 10, 2015
 * * Author: Hua Zhen
 * * (C) Copyright 2015, Hewlett-Packard Company, All Rights Reserved.
 * * This software is the proprietary information of HP, Inc.
 * * Use is subject to license terms.
 * ****************************************************************
 * * Description:
 * *   Get the DB cluster running status.
 * *
 ****************************************************************/
package com.hp.snap.gr.action.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.hp.snap.gr.db.voltdb.ControlDRAgent;
import com.hp.snap.gr.db.voltdb.VoltDBClientConfig;
import com.hp.snap.gr.exception.ActionException;
import com.hp.snap.gr.model.DBStatusInfo;
import com.hp.snap.gr.model.DRAgent;
import com.hp.snap.gr.model.Database;
import com.hp.snap.gr.model.jaxb.ActionType;
import com.hp.snap.gr.model.jaxb.GeneralActionType;
import com.hp.snap.gr.model.jaxb.ParameterType;
import com.hp.snap.gr.utils.Constants;
import com.hp.snap.gr.utils.GRMConfigManager;
import com.hp.snap.gr.utils.RESTfulUtils;
import com.hp.snap.gr.utils.Utils;

/**
 * Get the DB cluster running status by calling "@Statistics" system store procedure and put it to action output
 * parameters, the output parameter name format is: "DBStatusInfo"+DBInstanceName
 *
 *
 * There are one parameter can be configured in the action, DB_INSTANCE_NAME.
 *
 * DB_INSTANCE_NAME: The VoltDB DB instance name, such as: spr_db, session_db, lb_db.
 *
 * Action output: 
 *   DBStatusInfo: The type of this is 'Map<String, DBStatusInfo>'
 *       1) DBStatusCheckedInfo
 *
 *
 * Date: 18/1/2016
 *
 **/
public class GetIMDBVoltDBStatusActionHandler extends AbstractActionHandler {

    private static Logger logger = LoggerFactory.getLogger(GetIMDBVoltDBStatusActionHandler.class);

    @Override
    public void execute(ActionType action,
            Map<String, Object> actionPlanInputs,
            Map<String, Object> actionPlanOutputs) throws ActionException {
        GeneralActionType actionType = (GeneralActionType) action;
        List<ParameterType> parameterTypes = actionType.getParameter();
        Map<String, String> parameterMap = Utils.contructParamMap(parameterTypes);
        /**
         * get the db instance name, which should be configured in: /SNAP/GR/<DEPLOY_NAME>/VOLTDB/<DB_INSTANCE_NAME>, e.g.
         * /SNAP/GR/Site_A1/VOLTDB/session_db]
         */
        String dbInstName = parameterMap.get("DB_INSTANCE_NAME");
        if (StringUtils.isEmpty(dbInstName)) {
            throw new ActionException("The parameter [DB_INSTANCE_NAME] should be configured!");
        }

        // find out the target database profile
        Database database = null;

        try {
            database = RESTfulUtils.getVoltDBDatabase(dbInstName);

            if (database == null) {
                throw new ActionException("The database instance[" + dbInstName + "] is not existent");
            }
        } catch (Exception e) {
            logger.warn("Cannot get information from VEM of " + GRMConfigManager.getSiteName() + ":" + dbInstName);
            if (logger.isDebugEnabled()) {
                logger.debug(Utils.stackTraceToString(e));
            }
        }

        // set local db info
        Map<String, DBStatusInfo> dbStatusMap = null;
        if (actionPlanOutputs.containsKey(Constants.DB_STATUS_INFO_LOCAL)) {
            dbStatusMap = (Map<String, DBStatusInfo>) actionPlanOutputs.get(Constants.DB_STATUS_INFO_LOCAL);
        }
        if (dbStatusMap == null) {
            dbStatusMap = new HashMap<String, DBStatusInfo>();
        }
        DBStatusInfo localDBStatusInfo = getDBStatusInfo(GRMConfigManager.getSiteName(), dbInstName, database, false);
        dbStatusMap.put(dbInstName, localDBStatusInfo);
        actionPlanOutputs.put(Constants.DB_STATUS_INFO_LOCAL, dbStatusMap);

        //checking node available and lost node, 0:OK, 1:WARN, 2:ERROR
        int checkResult = 0;
        if (!"running".equals(localDBStatusInfo.getRunningStatus())) {
            checkResult = 2;
        }
        // output to shell command
        Constants.CONSOLE.info(dbInstName.toUpperCase() + "_OUTPUT:" + checkResult);

        String dbStatusInfoJson = new Gson().toJson(localDBStatusInfo, DBStatusInfo.class);
        if (logger.isDebugEnabled()) {
            logger.debug("current local db instance [(" + dbInstName + ")] status is {" + dbStatusInfoJson + "}");
        }

    }

    private DBStatusInfo getDBStatusInfo(String siteName, String dbInstName, Database database, boolean isRemote)
            throws ActionException {

        String status = "NA";
        String replicaStr = "NA";
        DRAgent drAgentInfo = new DRAgent();
        if (database != null) {
            status = database.getStatus();
            replicaStr = database.isReplica() ? "REPLICA" : "MASTER";
            // get db configuration
            List<VoltDBClientConfig> dbClientConfig = null;

            if (!Constants.VDB_STATUS_OFFLINE.endsWith(database.getStatus())) {
                try {
                    dbClientConfig = ControlDRAgent.getVoltDBClientConfig(database, siteName);
                } catch (ActionException e) {
                    if (logger.isDebugEnabled()) {
                        logger.debug(
                                "Can not get configurations of [" + database + "] on remote site[" + siteName + "]!", e
                                .getMessage());
                    }
                }
            }
            drAgentInfo = ControlDRAgent.getDRAgentStatusInfo(dbInstName, dbClientConfig, isRemote);
        }
        //set db info
        DBStatusInfo dbStatusInfo = new DBStatusInfo();
        dbStatusInfo.setDbName(dbInstName);
        dbStatusInfo.setDrAgent(drAgentInfo);
        dbStatusInfo.setRunningMode(replicaStr);
        dbStatusInfo.setRunningStatus(status);
        return dbStatusInfo;
    }
}
